﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace FrameWork.Setting
{
    /// <summary>
    /// 为设定属性提供集合存储
    /// </summary>
    public class SettingPropertyCollection : List<SettingPropertyInfoContainer>, ICustomTypeDescriptor
    {

        #region========外部实现========

        public AttributeCollection GetAttributes()
        {
            return TypeDescriptor.GetAttributes(this, true);
        }

        public string GetClassName()
        {
            return TypeDescriptor.GetClassName(this, true);
        }

        public string GetComponentName()
        {
            return TypeDescriptor.GetComponentName(this, true);
        }

        public TypeConverter GetConverter()
        {
            return TypeDescriptor.GetConverter(this, true);
        }

        public EventDescriptor GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(this, true);
        }

        public PropertyDescriptor GetDefaultProperty()
        {
            return TypeDescriptor.GetDefaultProperty(this, true);
        }

        public object GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(this, editorBaseType, true);
        }

        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(this, attributes, true);
        }

        public EventDescriptorCollection GetEvents()
        {
            return TypeDescriptor.GetEvents(this, true);
        }

        #endregion

        #region========内部实现========

        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {

            PropertyDescriptorCollection propDes = new PropertyDescriptorCollection(new PropertyDescriptor[0]);
            for (int i = 0; i < this.Count; i++)
            {
                SettingPropertyInfoContainer info = this[i];
                IEnumerable<Attribute> Attrs=info.BaseInfo.GetCustomAttributes();
                bool IsPicked=true;
                foreach(Attribute Attr in attributes)
                {
                    if(!Attrs.Contains(Attr))
                    {
                        IsPicked = false;
                        break;
                    }
                }
                if(IsPicked)
                    propDes.Add(new SettingPropertyDescriptor(ref info));
            }
            return propDes;
        }

        public PropertyDescriptorCollection GetProperties()
        {
            PropertyDescriptor[] propDes = new PropertyDescriptor[this.Count];
            for (int i = 0; i < this.Count; i++)
            {
                SettingPropertyInfoContainer info = this[i];
                propDes[i] = new SettingPropertyDescriptor(ref info);
            }
            return new PropertyDescriptorCollection(propDes);
        }

        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }

        #endregion

    }
    /// <summary>
    /// 为设定属性提供信息存储
    /// </summary>
    public class SettingPropertyInfoContainer
    {
        /// <summary>
        /// 表示基础属性信息实例
        /// </summary>
        public PropertyInfo BaseInfo { get; private set; }
        /// <summary>
        /// 表示基础属性是否与设定属性相连接
        /// </summary>
        public bool IsLinked { get; private set; }
        /// <summary>
        /// 表示基础设置对象实例
        /// </summary>
        public object BaseObject { get; private set; }

        private object ValueV;
        /// <summary>
        /// 表示该属性的值
        /// </summary>
        public object Value
        {
            get
            {
                if (BaseInfo == null || !IsLinked)
                    return ValueV;
                else
                    return BaseInfo.GetValue(BaseObject);
            }
            set
            {
                if (BaseInfo == null || !IsLinked)
                    ValueV = value;
                else
                    BaseInfo.SetValue(BaseObject, ValueV);
            }
        }
        /// <summary>
        /// 通过指定属性信息实例初始化设定属性实例
        /// </summary>
        /// <param name="BaseInfo">绑定的属性信息实例</param>
        /// <param name="BaseObject">绑定的基础对象</param>
        /// <param name="IsLinked">表示是否连接该属性，若连接则所有对值的操作都将是对该属性值的操作</param>
        public SettingPropertyInfoContainer(PropertyInfo BaseInfo, object BaseObject, bool IsLinked)
        {
            this.BaseInfo = BaseInfo;
            this.BaseObject = BaseObject;
            this.IsLinked = IsLinked;
            this.Value = BaseInfo.GetValue(BaseObject);
            //TypeDescriptor.AddAttributes(this, BaseInfo.GetCustomAttributes().ToArray());
        }
    }
    /// <summary>
    /// 为设定属性提供描述
    /// </summary>
    public class SettingPropertyDescriptor : PropertyDescriptor
    {
        public SettingPropertyInfoContainer SelectedProp { get; private set; }
        public SettingPropertyDescriptor(ref SettingPropertyInfoContainer property)
            : base(property.BaseInfo.Name, property.BaseInfo.GetCustomAttributes().ToArray())
        {
            SelectedProp = property;
        }

        public override bool CanResetValue(object component)
        {

            DefaultValueAttribute Attr = component.GetType().GetCustomAttribute<DefaultValueAttribute>();
            if (Attr != null)
                return true;
            else
                return false;
        }

        public override Type ComponentType
        {
            get { return SelectedProp.BaseInfo.PropertyType; }
        }

        public override object GetValue(object component)
        {
            return SelectedProp.Value;
        }

        public override bool IsReadOnly
        {
            get 
            {
                ReadOnlyAttribute[] Attrs = AttributeArray.OfType<ReadOnlyAttribute>().ToArray();
                if(Attrs.Count()>0)
                {
                    ReadOnlyAttribute Attr = Attrs[0];
                    return Attr.IsReadOnly;
                }
                else
                {
                    return false;
                }
            }
        }

        public override Type PropertyType
        {
            get { return SelectedProp.Value.GetType(); }
        }

        public override void ResetValue(object component)
        {
            DefaultValueAttribute Attr = component.GetType().GetCustomAttribute<DefaultValueAttribute>();
            if (Attr != null)
                SelectedProp.Value = Attr.Value;
        }

        public override void SetValue(object component, object value)
        {
            SelectedProp.Value = value;
        }

        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
    }

}
